/**
* @file exception.cpp
* Code for handle critical system exceptions.
*
* Copyrights 2010 Michal Saman, m.saman@designplus.cz
* This source code is release under the Apache License 2.0.
* http://www.apache.org/licenses/LICENSE-2.0
*/

#include <stdint.h>
#include <cpu/exception.h>
#include <hal/hal.h>

extern void kernel_panic(const char *fmt, ...) __attribute__ ((cdecl));

/**
* Install basic exception handler for CPU IRQs.
*/
__attribute__ ((cdecl)) void exceptions_install() {
	set_handler_interrupt(0, (void (*)(void))divide_by_zero_fault);
	set_handler_interrupt(1, (void (*)(void))single_step_trap);
	set_handler_interrupt(2, (void (*)(void))nmi_trap);
	set_handler_interrupt(3, (void (*)(void))breakpoint_trap);
	set_handler_interrupt(4, (void (*)(void))overflow_trap);
	set_handler_interrupt(5, (void (*)(void))bound_check_fault);
	set_handler_interrupt(6, (void (*)(void))invalid_opcode_fault);
	set_handler_interrupt(7, (void (*)(void))no_device_fault);
	set_handler_interrupt(8, (void (*)(void))double_fault_abort);
	set_handler_interrupt(10, (void (*)(void))invalid_tss_fault);
	set_handler_interrupt(11, (void (*)(void))no_segment_fault);
	set_handler_interrupt(12, (void (*)(void))stack_fault);
	set_handler_interrupt(13, (void (*)(void))general_protection_fault);
	set_handler_interrupt(14, (void (*)(void))page_fault);
	set_handler_interrupt(16, (void (*)(void))fpu_fault);
	set_handler_interrupt(17, (void (*)(void))aligment_check_fault);
	set_handler_interrupt(18, (void (*)(void))machine_check_abort);
	set_handler_interrupt(19, (void (*)(void))simd_fpu_fault);
}

extern void __attribute__ ((cdecl)) divide_by_zero_fault(uint32_t cs, uint32_t eip, uint32_t eflags) {
	kernel_panic("Divide by 0");
}

extern void __attribute__ ((cdecl)) single_step_trap(uint32_t cs, uint32_t eip, uint32_t eflags) {
	kernel_panic("Singele step");
}

extern void __attribute__ ((cdecl)) nmi_trap(uint32_t cs, uint32_t eip, uint32_t eflags) {
	kernel_panic("NMI trap");
}

extern void __attribute__ ((cdecl)) breakpoint_trap(uint32_t cs, uint32_t eip, uint32_t eflags) {
	kernel_panic("Breakpoint trap");
}

extern void __attribute__ ((cdecl)) overflow_trap(uint32_t cs, uint32_t eip, uint32_t eflags) {
	kernel_panic("Overflow trap");
}

extern void __attribute__ ((cdecl)) bound_check_fault(uint32_t cs, uint32_t eip, uint32_t eflags) {
	kernel_panic("Bonus check fault");
}

extern void __attribute__ ((cdecl)) invalid_opcode_fault(uint32_t cs, uint32_t eip, uint32_t eflags) {
	kernel_panic("Invalid opcode");
}

extern void __attribute__ ((cdecl)) no_device_fault(uint32_t cs, uint32_t eip, uint32_t eflags) {
	kernel_panic("Device not found");
}

extern void __attribute__ ((cdecl)) double_fault_abort(uint32_t cs, uint32_t err, uint32_t eip, uint32_t eflags) {
	kernel_panic("Double fault");
}

extern void __attribute__ ((cdecl)) invalid_tss_fault(uint32_t cs, uint32_t err, uint32_t eip, uint32_t eflags) {
	kernel_panic("Invalid TSS");
}

extern void __attribute__ ((cdecl)) no_segment_fault(uint32_t cs, uint32_t err, uint32_t eip, uint32_t eflags) {
	kernel_panic("Invalid segment");
}

extern void __attribute__ ((cdecl)) stack_fault(uint32_t cs, uint32_t err, uint32_t eip, uint32_t eflags) {
	kernel_panic("Stack fault");
}

extern void __attribute__ ((cdecl)) general_protection_fault(uint32_t cs, uint32_t err, uint32_t eip, uint32_t eflags) {
	kernel_panic("General Protection Fault");
}

extern void __attribute__ ((cdecl)) page_fault(uint32_t cs, uint32_t err, uint32_t eip, uint32_t eflags) {
	void* page_addr = 0;
	__asm__ volatile (
		"mov %%cr2, %0" : "=r"(page_addr)
	);
	//for (;;) {}
	kprintf("\n\nPageFault address 0x%x\n\n", page_addr);
	//kernel_panic("Page fault for page address 0x%x", page_addr);
}

extern void __attribute__ ((cdecl)) fpu_fault(uint32_t cs, uint32_t eip, uint32_t eflags) {
	kernel_panic("FPU Fault");
}

extern void __attribute__ ((cdecl)) aligment_check_fault(uint32_t cs, uint32_t err, uint32_t eip, uint32_t eflags) {
	kernel_panic("Aligment Check");
}

extern void __attribute__ ((cdecl)) machine_check_abort(uint32_t cs, uint32_t eip, uint32_t eflags) {
	kernel_panic("Machine Check");
}

extern void __attribute__ ((cdecl)) simd_fpu_fault(uint32_t cs, uint32_t eip, uint32_t eflags) {
	kernel_panic("FPU SIMD Fault");
}
